﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Threading;
using System.Drawing.Design;
using OpenComposite.Workflow.Properties;
using System.Runtime.Serialization;


namespace OpenComposite.Workflow
{
	[Designer(typeof(ComplexDesigner), typeof(IDesigner))]
	[ToolboxItem(typeof(ComplexActivityToolboxItem))]
	[ToolboxBitmap(typeof(resfinder), "OpenComposite.Workflow.Resources.complex.PNG")]
	public partial class ComplexActivity : DecisionActivity
	{
		public static readonly DependencyProperty CountProperty = DependencyProperty.Register("Count", typeof(int), typeof(ComplexActivity));

		[DescriptionAttribute("Count")]
		[Browsable(true)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		public int Count
		{
			get { return (int)GetValue(CountProperty); }
			set { base.SetValue(CountProperty, value); }
		}

		private int _currentCounter = 0;

		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			if ( EnabledActivities.Count == 0 )
				return ActivityExecutionStatus.Closed;

			foreach ( Activity child in EnabledActivities ) {
				child.Closed += new EventHandler<ActivityExecutionStatusChangedEventArgs>(ContinueAt);
				executionContext.ExecuteActivity(child);
			}
			return ActivityExecutionStatus.Executing;
		}

		void ContinueAt(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
			e.Activity.Closed -= this.ContinueAt;
			_currentCounter++;
			ActivityExecutionContext context = sender as ActivityExecutionContext;

			if ( _currentCounter == Count ) {
				foreach ( ActivityExecutionContext ctx in context.ExecutionContextManager.ExecutionContexts ) {
					if ( ctx.Activity.ExecutionStatus == ActivityExecutionStatus.Executing )
						ctx.CancelActivity(ctx.Activity);
				}

				ActivityExecutionContext subctx = null;
				foreach ( Activity child in EnabledActivities ) {
					ActivityExecutionStatus status = child.ExecutionStatus;
					if ( status == ActivityExecutionStatus.Executing ) {
						context.CancelActivity(child);
						child.Closed += new EventHandler<ActivityExecutionStatusChangedEventArgs>(ContinueAt);
						subctx = context.ExecutionContextManager.CreateExecutionContext(child);
						context.ExecutionContextManager.CompleteExecutionContext(subctx);
						//subctx.CloseActivity();
					}
				}
				//context.CancelActivity(context.Activity);
			} else if ( _currentCounter > Count ) {
				try {
					context.CloseActivity();
				} catch ( Exception ex ) {
					MessageBox.Show("Complex continueAt" + Environment.NewLine + ex.ToString());
				}
			}
		}
	}

	public partial class ComplexDesigner : DecisionDesigner
	{
		private Pen innerSymbolPenS = new Pen(Brushes.Black, 2.0F);
		private Pen innerSymbolPenM = new Pen(Brushes.Black, 3.0F);

		#region Paint Methods
		protected override void PaintSplit(ActivityDesignerPaintEventArgs e)
		{
			base.PaintSplit(e);

			bounds.Inflate(-10, -10);

			int x1 = bounds.Left;
			int x2 = bounds.Right;
			int x3 = x1 + (int)( ( x2 - x1 ) / 2 );
			int y1 = bounds.Top;
			int y2 = bounds.Bottom;
			int y3 = y1 + (int)( ( y2 - y1 ) / 2 );

			// +
			e.Graphics.DrawLine(innerSymbolPenM, x1, y3, x2, y3); // draw horizontal line
			e.Graphics.DrawLine(innerSymbolPenM, x3, y1, x3, y2); // draw vertical line

		}

		protected override void PaintJoin(ActivityDesignerPaintEventArgs e)
		{
			base.PaintJoin(e);

			bounds.Inflate(-10, -10);

			int x1 = bounds.Left;
			int x2 = bounds.Right;
			int x3 = x1 + (int)( ( x2 - x1 ) / 2 );
			int y1 = bounds.Top;
			int y2 = bounds.Bottom;
			int y3 = y1 + (int)( ( y2 - y1 ) / 2 );

			e.Graphics.DrawLine(innerSymbolPenS,
				x1, y3, x2, y3); // draw horizontal line
			e.Graphics.DrawLine(innerSymbolPenS,
				x3, y1, x3, y2); // draw vertical line

			bounds.Inflate(-3, -3);

			e.Graphics.DrawLine(innerSymbolPenS,
				bounds.Left, bounds.Top, bounds.Right, bounds.Bottom); // draw horizontal line
			e.Graphics.DrawLine(innerSymbolPenS,
				bounds.Right, bounds.Top, bounds.Left, bounds.Bottom); // draw vertical line

		}
		#endregion

		protected override void Dispose(bool disposing)
		{
			innerSymbolPenS.Dispose();
			innerSymbolPenM.Dispose();

			base.Dispose(disposing);
		}

		//protected override int SplitInflate
		//{
		//    get { return -13; }
		//}

		public override bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
		{
			if ( activitiesToInsert.Count == 0 )
				return false;

			if ( activitiesToInsert[0] is ConditionalBranchActivity )
				return true;
			else
				return false;
		}
	}

	[Serializable]
	public class ComplexActivityToolboxItem : ActivityToolboxItem
	{
		public ComplexActivityToolboxItem(Type type)
			: base(type)
		{
			this.DisplayName = "N out of M";
		}

		private ComplexActivityToolboxItem(SerializationInfo info, StreamingContext context)
		{
			Deserialize(info, context);
		}
	}
}